package com.frank.oj.service.oj.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.frank.model.entity.training.TrainingCategory;
import com.frank.model.entity.training.TrainingProblem;
import com.frank.oj.common.exception.StatusAccessDeniedException;
import com.frank.oj.common.exception.StatusFailException;
import com.frank.oj.common.exception.StatusForbiddenException;
import com.frank.oj.common.result.CommonResult;
import com.frank.oj.common.result.ResultStatus;
import com.frank.oj.manager.TrainingManager;
import com.frank.oj.mapper.TrainingMapper;
import com.frank.oj.model.dto.RegisterTrainingDTO;
import com.frank.oj.model.vo.AccessVO;
import com.frank.oj.model.vo.ProblemVO;
import com.frank.oj.model.vo.TrainingRankVO;
import com.frank.oj.model.vo.TrainingVO;
import com.frank.oj.service.entity.training.TrainingCategoryEntityService;
import com.frank.oj.service.entity.training.TrainingProblemEntityService;
import com.frank.oj.service.oj.TrainingService;
import com.frank.oj.shiro.AccountProfile;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author frank
 * @Date 2024/3/23
 */
@Service
public class TrainingServiceImpl implements TrainingService {
    @Resource
    private TrainingMapper trainingMapper;
    @Resource
    private TrainingManager trainingManager;
    @Resource
    private TrainingProblemEntityService trainingProblemEntityService;
    @Resource
    private TrainingCategoryEntityService trainingCategoryEntityService;

    @Override
    public CommonResult<IPage<TrainingVO>> getTrainingList(Integer limit, Integer currentPage, String keyword, Long categoryId, String auth) {

        if (currentPage == null || currentPage < 1) currentPage = 1;
        if (limit == null || limit < 1) limit = 10;

        Page<TrainingVO> page = new Page<>(currentPage, limit);



        AccountProfile userRoleVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();

        String currentUid = null; // 当前用户id
        if (userRoleVo != null) {
            currentUid = userRoleVo.getUid();
        }

        List<TrainingVO> trainingList = trainingMapper.getTrainingList(page, categoryId, auth, keyword);

        //当用户有登录，且训练列表不为空时，查询用户在每个训练的做题进度
        if (!StringUtils.isEmpty(currentUid) && !trainingList.isEmpty()) {
            // 获取所有训练的id
            List<Long> tidList = trainingList.stream().map(TrainingVO::getId).collect(Collectors.toList());

            // 获取用户在每个训练的做题进度
            List<TrainingProblem> trainingProblemList = trainingProblemEntityService.getTrainingListAcceptedCountByUid(tidList, currentUid);

            Map<Long, Integer> tidCountMap = new HashMap<>(trainingList.size());

            for (TrainingProblem trainingProblem : trainingProblemList) {
                int count = tidCountMap.getOrDefault(trainingProblem.getTid(), 0);
                count++;
                tidCountMap.put(trainingProblem.getTid(), count);
            }

            // 存入list
            for (TrainingVO trainingVO : trainingList) {
                int count = tidCountMap.getOrDefault(trainingVO.getId(), 0);
                trainingVO.setAcCount(count);
            }
        }
        page.setRecords(trainingList);
        return CommonResult.successResponse(page);

    }

    @Override
    public CommonResult<List<TrainingCategory>> getTrainingCategory() {
        return CommonResult.successResponse(trainingCategoryEntityService.getTrainingCategory());
    }

    @Override
    public CommonResult<TrainingVO> getTrainingDetail(Long tid) {
        try {
            return CommonResult.successResponse(trainingManager.getTraining(tid));
        } catch (StatusFailException e) {
            return CommonResult.errorResponse(e.getMessage());
        } catch (StatusAccessDeniedException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.ACCESS_DENIED);
        } catch (StatusForbiddenException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.FORBIDDEN);
        }
    }

    @Override
    public CommonResult<List<ProblemVO>> getTrainingProblemList(Long tid) {
        try {
            return CommonResult.successResponse(trainingManager.getTrainingProblemList(tid));
        } catch (StatusFailException e) {
            return CommonResult.errorResponse(e.getMessage());
        } catch (StatusAccessDeniedException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.ACCESS_DENIED);
        } catch (StatusForbiddenException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.FORBIDDEN);
        }
    }

    @Override
    public CommonResult<AccessVO> getTrainingAccess(Long tid) {
        try {
            return CommonResult.successResponse(trainingManager.getTrainingAccess(tid));
        } catch (StatusFailException e) {
            return CommonResult.errorResponse(e.getMessage());
        }
    }

    @Override
    public CommonResult<Void> toRegisterTraining(RegisterTrainingDTO registerTrainingDto) {
        try {
            trainingManager.toRegisterTraining(registerTrainingDto);
            return CommonResult.successResponse();
        } catch (StatusFailException e) {
            return CommonResult.errorResponse(e.getMessage());
        } catch (StatusForbiddenException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.FORBIDDEN);
        }
    }

    @Override
    public CommonResult<IPage<TrainingRankVO>> getTrainingRank(Long tid, Integer limit, Integer currentPage, String keyword) {
        try {
            return CommonResult.successResponse(trainingManager.getTrainingRank(tid, limit, currentPage, keyword));
        } catch (StatusFailException e) {
            return CommonResult.errorResponse(e.getMessage());
        } catch (StatusAccessDeniedException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.ACCESS_DENIED);
        } catch (StatusForbiddenException e) {
            return CommonResult.errorResponse(e.getMessage(), ResultStatus.FORBIDDEN);
        }
    }
}
